﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Net.Http;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using DataService.Core.Log;
using System.Net.Mail;
using DataService.Core.Network;
using System.Reflection;
using DataService.Core.Extensions;
using System.Xml.Linq;

namespace DataService.Core.HttpClientHelper
{
    public class ContentTypeConst
    {
        public const string MultipartFormDataContentConst = "multipart/form-data";
        public const string FormUrlEncodedContentConst = "application/x-www-form-urlencoded";
        public const string StringContentConst = "application/json";
        public const string StreamContentConst = "binary";
        //MultipartFormDataContent=》multipart/form-data
        // FormUrlEncodedContent =》application / x - www - form - urlencoded
        //StringContent =》application / json等
        //StreamContent =》binary
    }
    public static class HttpClientHelper
    {
        private static HttpClient _HttpClientApp = null;

        private static HttpClient GetHttpClient()
        {
            if (_HttpClientApp == null)
            {
                _HttpClientApp = new HttpClient();
                _HttpClientApp.Timeout = TimeSpan.FromSeconds(60);
            }
            return _HttpClientApp;
        }
        /// <summary>
        /// http请求,post方式,上传单个文件
        /// </summary>
        /// <param name="buffer">文件流</param>
        /// <param name="fileName">文件名 如 xxx.xlsx</param>
        /// <param name="stringDict">需要发送的参数和值</param>
        public static string HttpFileRequestHelper(string url, byte[] buffer, string fileName, Dictionary<string, string> stringDict)
        {
            try
            {
                // 边界符
                var boundary = "---------------" + DateTime.Now.Ticks.ToString("x");
                var beginBoundary = Encoding.ASCII.GetBytes("--" + boundary + "\r\n");
                //  var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
                // 开始拼数据
                var memStream = new MemoryStream();
                // 最后的结束符
                var endBoundary = Encoding.ASCII.GetBytes("--" + boundary + "--\r\n");
                if (buffer != null)
                {
                    // 文件参数头
                    const string filePartHeader =
                    "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n" +
                     "Content-Type: application/octet-stream\r\n\r\n";
                    var fileHeader = string.Format(filePartHeader, "file", fileName);
                    var fileHeaderBytes = Encoding.UTF8.GetBytes(fileHeader);

                    memStream.Write(beginBoundary, 0, beginBoundary.Length);

                    // 文件数据
                    memStream.Write(fileHeaderBytes, 0, fileHeaderBytes.Length);

                    memStream.Write(buffer, 0, buffer.Length);
                }
                // Key-Value数据
                var stringKeyHeader = "\r\n--" + boundary +
                                       "\r\nContent-Disposition: form-data; name=\"{0}\"" +
                                       "\r\n\r\n{1}\r\n";
                if (stringDict != null && stringDict.Count > 0)
                {
                    foreach (byte[] formitembytes in from string key in stringDict.Keys
                                                     select string.Format(stringKeyHeader, key, stringDict[key])
                                         into formitem
                                                     select Encoding.UTF8.GetBytes(formitem))
                    {
                        memStream.Write(formitembytes, 0, formitembytes.Length);
                    }
                }


                // 写入最后的结束边界符
                memStream.Write(endBoundary, 0, endBoundary.Length);

                //倒腾到tempBuffer?
                memStream.Position = 0;
                var tempBuffer = new byte[memStream.Length];
                memStream.Read(tempBuffer, 0, tempBuffer.Length);
                memStream.Close();

                // 创建webRequest并设置属性
                var webRequest = (HttpWebRequest)WebRequest.Create(url);
                webRequest.Method = "POST";
                webRequest.Timeout = 100000;
                webRequest.ContentType = "multipart/form-data; boundary=" + boundary;
                webRequest.ContentLength = tempBuffer.Length;

                var requestStream = webRequest.GetRequestStream();
                requestStream.Write(tempBuffer, 0, tempBuffer.Length);
                requestStream.Close();

                var httpWebResponse = (HttpWebResponse)webRequest.GetResponse();
                string responseContent;
                using (var httpStreamReader = new StreamReader(httpWebResponse.GetResponseStream(), Encoding.GetEncoding("utf-8")))
                {
                    responseContent = httpStreamReader.ReadToEnd();
                }
                httpWebResponse.Close();
                webRequest.Abort();
                return responseContent;
            }
            catch (Exception ex)
            {
                TraceLog.WriteLine("批量生生成文件异常：" + ex.Message);
                throw ex;
            }
        }

        /// <summary>
        /// 接收方是NetFrameWork的WebAPI
        /// http请求,post，上传多个文件
        /// </summary>
        /// <param name="fileDic">文件流集合 key：文件名（含后缀） Value：文件流</param>
        /// <param name="paraDic">参数集合 key:参数名 Value:参数值</param>
        /// <param name="url"></param>
        /// <returns></returns>
        public static string HttpMultipleFileRequestHelper(string url, Dictionary<string, byte[]> fileDic, Dictionary<string, string> paraDic)
        {
            try
            {
                // 边界符
                var boundary = "---------------" + DateTime.Now.Ticks.ToString("x");
                var beginBoundary = Encoding.ASCII.GetBytes("--" + boundary + "\r\n");
                //  var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);

                // 最后的结束符
                var endBoundary = Encoding.ASCII.GetBytes("--" + boundary + "--\r\n");

                // 文件参数头
                string filePartHeader = "--" + boundary +
                   "\r\nContent-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n" +
                    "Content-Type: application/octet-stream\r\n\r\n";
                // 开始拼数据
                var memStream = new MemoryStream();
                memStream.Write(beginBoundary, 0, beginBoundary.Length);
                int i = 0;
                if (fileDic != null)
                {
                    foreach (var item in fileDic)
                    {
                        var fileHeader = string.Format(filePartHeader, "file" + i, item.Key);
                        var fileHeaderBytes = Encoding.UTF8.GetBytes(fileHeader);
                        // 文件数据
                        memStream.Write(fileHeaderBytes, 0, fileHeaderBytes.Length);
                        memStream.Write(item.Value, 0, item.Value.Length);
                        var stringKeyHeader = "\r\n";
                        byte[] formitembytes = Encoding.UTF8.GetBytes(stringKeyHeader);
                        memStream.Write(formitembytes, 0, formitembytes.Length);
                        i++;
                    }
                }

                if (paraDic != null && paraDic.Count > 0)
                {
                    // Key-Value数据
                    var stringKeyHeader = "\r\n--" + boundary +
                                           "\r\nContent-Disposition: form-data; name=\"{0}\"" +
                                           "\r\n\r\n{1}\r\n";
                    foreach (byte[] formitembytes in from string key in paraDic.Keys
                                                     select string.Format(stringKeyHeader, key, paraDic[key])
                                                     into formitem
                                                     select Encoding.UTF8.GetBytes(formitem))
                    {
                        memStream.Write(formitembytes, 0, formitembytes.Length);
                    }
                }
                else
                {
                    var stringKeyHeader = "\r\n";
                    byte[] formitembytes = Encoding.UTF8.GetBytes(stringKeyHeader);
                    memStream.Write(formitembytes, 0, formitembytes.Length);
                }
                // 写入最后的结束边界符
                memStream.Write(endBoundary, 0, endBoundary.Length);

                //倒腾到tempBuffer?
                memStream.Position = 0;
                var tempBuffer = new byte[memStream.Length];
                memStream.Read(tempBuffer, 0, tempBuffer.Length);
                memStream.Close();
                // 创建webRequest并设置属性
                var webRequest = (HttpWebRequest)WebRequest.Create(url);
                webRequest.Method = "POST";
                webRequest.Timeout = 100000;
                webRequest.ContentType = "multipart/form-data; boundary=" + boundary;
                webRequest.ContentLength = tempBuffer.Length;

                var requestStream = webRequest.GetRequestStream();
                requestStream.Write(tempBuffer, 0, tempBuffer.Length);
                requestStream.Close();

                var httpWebResponse = (HttpWebResponse)webRequest.GetResponse();
                string responseContent;
                using (var httpStreamReader = new StreamReader(httpWebResponse.GetResponseStream(), Encoding.GetEncoding("utf-8")))
                {
                    responseContent = httpStreamReader.ReadToEnd();
                }
                httpWebResponse.Close();
                webRequest.Abort();
                return responseContent;
            }
            catch (Exception ex)
            {
                TraceLog.WriteLine("批量生生成文件异常：" + ex.Message);
                throw ex;

            }
        }

        /// <summary>
        /// 调用文件接口,上传文件【接收方NetCore或者.NETFrameWork的webAPI】
        /// </summary>
        /// <param name="fileDic">key:文件名称(含后缀名) value:字节流</param>
        /// <param name="paraDic">key:参数名 value:参数值，接收端使用[FromForm]XXX实体名</param>
        /// <param name="url">调用方连接</param>
        /// <returns></returns>
        public static string HttpMultipleFileRequestHelper(string token, string url, Dictionary<string, byte[]> fileDic, Dictionary<string, string> paraDic, Dictionary<string, string> header)
        {
            try
            {
                if (fileDic == null || fileDic.Count == 0) return "没有需要上传的文件";
                HttpClient httpClient = GetHttpClient();
                var httpRequest = GetHttpRequestMessageHeader(url, header, token);
                using (MultipartFormDataContent httpContent = new MultipartFormDataContent())
                {
                    if (paraDic != null)
                    {
                        foreach (var item in paraDic)
                        {
                            httpContent.Add(new StringContent(item.Value), item.Key);
                        }
                    }
                    List<Stream> streamList = new List<Stream>();
                    List<StreamContent> StreamContentList = new List<StreamContent>();
                    //添加文件流参数
                    foreach (var item in fileDic)
                    {
                        Stream stream = new MemoryStream(item.Value);
                        streamList.Add(stream);
                        StreamContent streamContent = new StreamContent(stream);
                        httpContent.Add(streamContent, Guid.NewGuid().ToString(), item.Key);
                        StreamContentList.Add(streamContent);
                    }
                    // httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(ContentTypeConst.MultipartFormDataContentConst);
                    httpRequest.Content = httpContent;
                    string responseJson = httpClient.SendAsync(httpRequest).Result.Content.ReadAsStringAsync().Result;
                    foreach (var item in streamList)
                    {
                        DisponseStream(item);
                    }
                    foreach (var item in StreamContentList)
                    {
                        DisponseHttpContext(item);
                    }

                    return responseJson;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }

        /// <summary>
        /// 调用文件接口,上传文件【接收方NetCore或者.NETFrameWork的webAPI】
        /// </summary>
        /// <param name="fileDic">key:文件名称(含后缀名) value:字节流</param>
        /// <param name="paraDic">key:参数名 value:参数值，接收端使用[FromForm]XXX实体名</param>
        /// <param name="url">调用方连接</param>
        /// <returns></returns>
        public static string HttpMultipleFileRequestHelper<T>(string token,string url, Dictionary<string, byte[]> fileDic, T t, Dictionary<string, string> header)
        {
            try
            {
                if (fileDic == null || fileDic.Count == 0) return "没有需要上传的文件";
                HttpClient httpClient = GetHttpClient();
                var httpRequest = GetHttpRequestMessageHeader(url, header,token);
                using (MultipartFormDataContent httpContent = new MultipartFormDataContent())
                {
                    if (t != null)
                    {
                        Dictionary<string, string> paraDic = GetDictionaryByPropertyInfo<T>(t);
                        if (paraDic != null)
                        {
                            foreach (var item in paraDic)
                            {
                                httpContent.Add(new StringContent(item.Value), item.Key);
                            }
                        }
                    }
                    List<Stream> streamList = new List<Stream>();
                    List<StreamContent> StreamContentList = new List<StreamContent>();
                    //添加文件流参数
                    foreach (var item in fileDic)
                    {
                        Stream stream = new MemoryStream(item.Value);
                        streamList.Add(stream);
                        StreamContent streamContent = new StreamContent(stream);
                        StreamContentList.Add(streamContent);
                        httpContent.Add(streamContent, Guid.NewGuid().ToString(), item.Key);
                    }
                    //httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(ContentTypeConst.MultipartFormDataContentConst);
                    httpRequest.Content = httpContent;
                    string responseJson = httpClient.SendAsync(httpRequest).Result.Content.ReadAsStringAsync().Result;
                    foreach (var item in streamList)
                    {
                        DisponseStream(item);
                    }
                    foreach (var item in StreamContentList)
                    {
                        DisponseHttpContext(item);
                    }

                    return responseJson;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }


        /// <summary>
        /// 调用API接口
        /// </summary>
        /// <param name="paraDic">key:参数名 value:参数值，接收端使用[FromForm]XXX实体名</param>
        /// <param name="url"></param>
        /// <returns></returns>
        public static string HttpRequestHelper(string token,string url, Dictionary<string, string> paraDic, Dictionary<string, string> header)
        {
            HttpClient httpClient = GetHttpClient();
            try
            {
                var httpRequest = GetHttpRequestMessageHeader(url, header,token);
                paraDic = paraDic ?? new Dictionary<string, string>();
                using (FormUrlEncodedContent httpContent = new FormUrlEncodedContent(paraDic))
                {
                    httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(ContentTypeConst.FormUrlEncodedContentConst);
                    httpRequest.Content = httpContent;
                    string responseJson = httpClient.SendAsync(httpRequest).Result.Content.ReadAsStringAsync().Result;
                    // string responseJson = httpClient.PostAsync(url, new FormUrlEncodedContent(paraDic)).Result.Content.ReadAsStringAsync().Result;

                    return responseJson;
                }




            }
            catch (Exception ex)
            {
                TraceLog.WriteLine("异常的：" + httpClient.GetHashCode());
                throw ex;
            }

        }
        /// <summary>
        /// 调用API接口
        /// </summary>
        /// <param name="T">
        /// 接收端使用[FromForm]XXX实体名,如果t是list集合请调用HttpRequestHelperByBody
        /// </param>
        /// <param name="url"></param>
        /// <returns></returns>
        public static string HttpRequestHelperByForm<T>(string token,string url, T t, Dictionary<string, string> header) where T : class
        {
            try
            {
                HttpClient httpClient = GetHttpClient();
                var httpRequest = GetHttpRequestMessageHeader(url, header, token);

                Dictionary<string, string> paraDic = new Dictionary<string, string>();
                if (t != null)
                {
                    paraDic = GetDictionaryByPropertyInfo<T>(t);
                }
                using (FormUrlEncodedContent httpContent = new FormUrlEncodedContent(paraDic))
                {
                    httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(ContentTypeConst.FormUrlEncodedContentConst);
                    httpRequest.Content = httpContent;
                    string responseJson = httpClient.SendAsync(httpRequest).Result.Content.ReadAsStringAsync().Result;
                    // httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
                    //string responseJson = httpClient.PostAsync(url, httpContent).Result.Content.ReadAsStringAsync().Result;


                    return responseJson;
                }


            }
            catch (Exception ex)
            {

                throw ex;
            }

        }
        /// <summary>
        /// 调用API接口
        /// </summary>
        /// <param name="T">接收端使用[FromBody]XXX实体名</param>
        /// <param name="url"></param>
        /// <returns></returns>
        public static string HttpRequestHelperByBody<T>(string token, string url, T t, Dictionary<string, string> header) where T : class
        {
            try
            {
                HttpClient httpClient = GetHttpClient();
                var httpRequest = GetHttpRequestMessageHeader(url, header, token);
                string parameterjson = DataService.Core.Json.JsonHelper.ToJson(t);
                using (System.Net.Http.StringContent httpContent = new System.Net.Http.StringContent(parameterjson))
                {
                    httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(ContentTypeConst.StringContentConst);
                    httpRequest.Content = httpContent;
                    string responseJson = httpClient.SendAsync(httpRequest).Result.Content.ReadAsStringAsync().Result;


                    return responseJson;
                }


            }
            catch (Exception ex)
            {
                throw ex;
            }
        }


        /// <summary>
        /// 调用API异步接口
        /// </summary>
        /// <param name="T">接收端使用[FromBody]XXX实体名</param>
        /// <param name="url"></param>
        /// <returns></returns>
        public static Task<string> HttpAsyncRequestHelperByBody<T>(string token, string url, T t, Dictionary<string, string> header) where T : class
        {
            try
            {
                HttpClient httpClient = GetHttpClient();
                var httpRequest = GetHttpRequestMessageHeader(url, header, token);
                string parameterjson = DataService.Core.Json.JsonHelper.ToJson(t);
                using (System.Net.Http.StringContent httpContent = new System.Net.Http.StringContent(parameterjson))
                {
                    httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(ContentTypeConst.StringContentConst);
                    httpRequest.Content = httpContent;
                    var task = httpClient.SendAsync(httpRequest).Result.Content.ReadAsStringAsync();
                    return task;
                }
            }
            catch (Exception)
            {

            }
            return new Task<string>(() => { return ""; });

        }

        private static HttpRequestMessage GetHttpRequestMessageHeader(string url, Dictionary<string, string> header,string token)
        {
            var httpRequestMessage = new HttpRequestMessage()
            {
                RequestUri = new Uri(url),
                Method = HttpMethod.Post
            };
            if (header != null && header.Count > 0)
            {
                foreach (var item in header)
                {
                    httpRequestMessage.Headers.Remove(item.Key);
                    httpRequestMessage.Headers.Add(item.Key, item.Value);//加头
                }
            }
            //登录成功之后，需要添加此 Authorization
            if (!string.IsNullOrEmpty(token))
            {
                httpRequestMessage.Headers.Remove("Authorization");
                httpRequestMessage.Headers.Add("Authorization", token);
            }
            httpRequestMessage.Headers.Remove("SecurityMsg");
            httpRequestMessage.Headers.Add("SecurityMsg", GetLoginMsg());
            // httpRequestMessage.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType);
            //httpRequestMessage.Headers.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue(contentType));
            return httpRequestMessage;
        }
        private static void FillHttpClient(HttpClient httpClient)
        {
            TraceLog.WriteLine("HttpClientCode：" + httpClient.GetHashCode());
            //httpClient.Timeout = TimeSpan.FromSeconds(3 * 60);
        }
        private static void DisponseStream(Stream stream)
        {
            try
            {
                stream.Dispose();
            }
            catch (Exception)
            {
            }

        }
        private static void DisponseHttpContext(HttpContent content)
        {
            try
            {
                content.Dispose();
            }
            catch (Exception)
            {
            }

        }
        private static Dictionary<string, string> GetDictionaryByPropertyInfo<T>(T t)
        {
            if (t == null) return null;
            Dictionary<string, string> dic = new Dictionary<string, string>();
            foreach (PropertyInfo item in typeof(T).GetProperties())
            {
               object val= MemberInfoHelper.GetPropertyValue(t, item);
                if (val != null)
                {
                    dic[item.Name] = val.ToString();
                }
                else
                {
                    dic[item.Name] = null;
                }
            }
            return dic;
        }
        private static string GetLoginMsg()
        {
            string macAddress = BitConverter.ToString(NetHelper.GetMac());
            return macAddress + "." + Guid.NewGuid().ToString();
        }
    }
}
